package com.zhz.common.tool.mybatisplus.base.dal.repository.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.enums.SqlMethod;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.GlobalConfigUtils;
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.zhz.common.tool.mybatisplus.base.core.contract.BaseParam;
import com.zhz.common.tool.mybatisplus.base.core.contract.Page;
import com.zhz.common.tool.mybatisplus.base.core.contract.PageParam;
import com.zhz.common.tool.mybatisplus.base.core.contract.SortParam;
import com.zhz.common.tool.mybatisplus.base.dal.annotation.BizKey;
import com.zhz.common.tool.mybatisplus.base.dal.entity.BasePO;
import com.zhz.common.tool.mybatisplus.base.dal.repository.BaseRepository;
import com.zhz.common.tool.mybatisplus.base.dal.utils.Converter;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.ibatis.binding.MapperMethod.ParamMap;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionHolder;
import org.mybatis.spring.SqlSessionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.Map.Entry;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public abstract class BaseRepositoryImpl<M extends BaseMapper<T>, D, T extends BasePO, Q extends BaseParam> implements BaseRepository<D, Q> {
    private static final Logger log = LoggerFactory.getLogger(BaseRepositoryImpl.class);
    @Autowired
    protected M baseMapper;
    private Class<D> dtoClass = (Class<D>) ReflectionKit.getSuperClassGenericType(this.getClass(), this.getClass().getSuperclass(),1);
    private Class<T> entityClass = (Class<T>) ReflectionKit.getSuperClassGenericType(this.getClass(), this.getClass().getSuperclass(),2);
    private TableScheme tableScheme;
    private static final Pattern HUMP_PATTERN = Pattern.compile("[A-Z]");
    private static final String START_QUERY = "start";
    private static final String END_QUERY = "end";
    private static final String SET_QUERY = "set";
    private static final String LIST_QUERY = "list";
    private static final String NOT_SET_QUERY = "notset";
    private static final String NOT_LIST_QUERY = "notlist";
    private static final String LIKE_QUERY = "like";
    private static final String LIKE_LEFT_QUERY = "likeleft";
    private static final String LIKE_RIGHT_QUERY = "likeright";
    private static final String MIN_QUERY = "min";
    private static final String MAX_QUERY = "max";
    private static final String MIN_EQUALS_QUERY = "mineq";
    private static final String MAX_EQUALS_QUERY = "maxeq";
    private static final String NOT_EQUALS_QUERY = "noteq";

    public BaseRepositoryImpl() {
        this.initTableInfo();
    }

    public boolean save(D dto) {
        T dbEntity = Converter.copy(dto, this.entityClass);
        boolean result = SqlHelper.retBool(this.baseMapper.insert(dbEntity));
        if (result) {
            this.copyProperties(dbEntity, dto);
        }

        return result;
    }

    @Transactional(rollbackFor = {Exception.class})
    public boolean save(Collection<D> dtoList) {
        List<T> dbEntityList = Converter.copy(dtoList, this.entityClass);
        boolean result = this.insertBatch(dbEntityList, 100);
        if (result) {
            this.copyProperties(dbEntityList, dtoList);
        }
        return result;
    }

    public boolean update(D dto) {
        T dbEntity = Converter.copy(dto, this.entityClass);
        boolean result = SqlHelper.retBool(this.baseMapper.updateById(dbEntity));
        if (result) {
            this.copyProperties(dbEntity, dto);
        }
        return result;
    }

    protected boolean update(D dto, Wrapper<T> updateWrapper) {
        T dbEntity = Converter.copy(dto, this.entityClass);
        boolean result = SqlHelper.retBool(this.baseMapper.update(dbEntity, updateWrapper));
        if (result) {
            this.copyProperties(dbEntity, dto);
        }

        return result;
    }

    @Transactional(rollbackFor = {Exception.class})
    public boolean update(Collection<D> dtoList) {
        Collection<T> dbEntityList = Converter.copy(dtoList, this.entityClass);
        boolean result = this.updateBatch(dbEntityList, 30);
        if (result) {
            this.copyProperties(dbEntityList, dtoList);
        }
        return result;
    }

    public boolean delete(Serializable id) {
        if (id == null) {
            return false;
        } else {
            int count = this.baseMapper.deleteById(id);
            return SqlHelper.retBool(count);
        }
    }

    public boolean delete(Collection<? extends Serializable> idList) {
        if (CollUtil.isEmpty(idList)) {
            log.warn("batch function param is empty or null");
            return false;
        } else {
            int count = this.baseMapper.deleteBatchIds(idList);
            return SqlHelper.retBool(count);
        }
    }

    protected boolean delete(Wrapper<T> deleteWrapper) {
        if (deleteWrapper != null && !deleteWrapper.isEmptyOfNormal()) {
            int count = this.baseMapper.delete(deleteWrapper);
            return SqlHelper.retBool(count);
        } else {
            return false;
        }
    }

    public List<D> list(Collection<? extends Serializable> idList) {
        if (CollUtil.isEmpty(idList)) {
            throw new IllegalArgumentException("Error: idList must not be empty");
        } else {
            Collection<T> entityList = this.baseMapper.selectBatchIds(idList);
            return Converter.copy(entityList, this.dtoClass);
        }
    }

    public List<D> list(Q queryParam) {
        Collection<T> entityList = this.baseMapper.selectList(this.getWrapper(queryParam));
        return Converter.copy(entityList, this.dtoClass);
    }

    public D first(Q queryParam) {
        Optional<T> optional = this.baseMapper.selectList(this.getWrapper(queryParam)).stream().findFirst();
        return optional.map((t) -> Converter.copy(t, this.dtoClass)).orElse(null);
    }

    public D getOne(Q queryParam) {
        T entity = this.baseMapper.selectOne(this.getWrapper(queryParam));
        return Converter.copy(entity, this.dtoClass);
    }

    public D get(Serializable id) {
        if (id == null) {
            throw new IllegalArgumentException("Error: id must not be null ");
        } else {
            T entity = this.baseMapper.selectById(id);
            return Converter.copy(entity, this.dtoClass);
        }
    }

    public int count(Q params) {
        return Math.toIntExact(this.baseMapper.selectCount(this.getWrapper(params)));
    }

    public Page<D> page(PageParam<Q> pageParam) {
        return this.page(pageParam.getPage(), pageParam.getLimit(), pageParam.getParam(), pageParam.getSorts());
    }

    public Page<D> page(long page, long limit, Q params) {
        return this.page(page, limit, params, Collections.emptyList());
    }

    public Page<D> page(long page, long limit, Q params, List<SortParam> sorts) {
        return this.page(page, limit, params, sorts, true);
    }

    public Page<D> page(long page, long limit, Q params, List<SortParam> sorts, boolean checkTheSortField) {
        QueryWrapper<T> wrapper = this.getWrapper(params);
        List orders;
        if (checkTheSortField) {
            orders = this.checkOrderBy(sorts, this.tableScheme);
        } else {
            orders = this.getOrderBy(sorts);
        }

        IPage<T> mpPage = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(page, limit);
        Iterator var11 = orders.iterator();

        while(var11.hasNext()) {
            OrderItem order = (OrderItem)var11.next();
            if (order.isAsc()) {
                wrapper.orderByAsc(order.getColumn());
            } else {
                wrapper.orderByDesc(order.getColumn());
            }
        }

        IPage<T> pageResult = this.baseMapper.selectPage(mpPage, wrapper);
        Page<T> Page = mapTo(pageResult);
        return (Page<D>) Converter.copy(Page, this.dtoClass);
    }

    public boolean deleteByKey(String key) {
        if (StringUtils.isBlank(key)) {
            return false;
        } else {
            int count = this.baseMapper.delete(this.getKeyWrapper(key));
            return BooleanUtils.toBoolean(count);
        }
    }

    public boolean deleteByKeys(Collection<String> keys) {
        if (CollUtil.isEmpty(keys)) {
            log.warn("batch function param is empty or null");
            return false;
        } else {
            int count = this.baseMapper.delete(this.getKeyWrapper(keys));
            return BooleanUtils.toBoolean(count);
        }
    }

    public boolean updateByKey(D dto) {
        T dbEntity = Converter.copy(dto, this.entityClass);
        String key = this.getKeyValue(dbEntity);
        if (StringUtils.isBlank(key)) {
            throw new IllegalArgumentException("当前entity实体业务key字段为null，无法适用当前方法更新！");
        } else {
            return SqlHelper.retBool(this.baseMapper.update(dbEntity, this.getKeyWrapper(key)));
        }
    }

    @Transactional(
            rollbackFor = {Exception.class}
    )
    public boolean updateByKey(Collection<D> dtoList) {
        if (CollUtil.isEmpty(dtoList)) {
            log.warn("batch function param is empty or null");
            return false;
        } else {
            Iterator<D> var2 = dtoList.iterator();

            while(var2.hasNext()) {
                D dto = var2.next();
                this.updateByKey(dto);
            }

            return true;
        }
    }

    public D getByKey(String key) {
        if (StringUtils.isBlank(key)) {
            throw new IllegalArgumentException("Error: key must not be blank ");
        } else {
            T entity = this.baseMapper.selectOne(this.getKeyWrapper(key));
            return Converter.copy(entity, this.dtoClass);
        }
    }

    public List<D> listByKey(Collection<String> keys) {
        if (CollUtil.isEmpty(keys)) {
            throw new IllegalArgumentException("Error: keys must not be empty");
        } else {
            Collection<T> entityList = this.baseMapper.selectList(this.getKeyWrapper(keys));
            return Converter.copy(entityList, this.dtoClass);
        }
    }

    protected QueryWrapper<T> getWrapper(Map<String, Object> mapParams) {
        QueryWrapper<T> wrapper = this.getDefaultWrapper();
        if (mapParams == null) {
            return wrapper;
        } else {
            Iterator var3 = mapParams.entrySet().iterator();

            while(true) {
                while(true) {
                    Entry item;
                    do {
                        do {
                            if (!var3.hasNext()) {
                                return wrapper;
                            }

                            item = (Entry)var3.next();
                        } while(item.getValue() == null);
                    } while(this.isStringBlank(item.getValue()));

                    String key = ((String)item.getKey()).toLowerCase();
                    Object value = item.getValue();
                    if (key.startsWith(START_QUERY) && this.isDateType(value)) {
                        this.getColumnByField(key.replaceFirst(START_QUERY, ""), (p) -> wrapper.ge(p, value));
                    } else if (key.startsWith(END_QUERY) && this.isDateType(value)) {
                        this.getColumnByField(key.replaceFirst(END_QUERY, ""), (p) -> wrapper.le(p, value));
                    }

                    if (key.endsWith(MIN_EQUALS_QUERY) && this.isNumericType(value)) {
                        this.getColumnByField(this.getFieldName(key, MIN_EQUALS_QUERY), (p) -> wrapper.ge(p, value));
                    } else if (key.endsWith(MAX_EQUALS_QUERY) && this.isNumericType(value)) {
                        this.getColumnByField(this.getFieldName(key, MAX_EQUALS_QUERY), (p) -> wrapper.le(p, value));
                    }

                    if (key.endsWith(MIN_QUERY) && this.isNumericType(value)) {
                        this.getColumnByField(this.getFieldName(key, MIN_QUERY), (p) -> wrapper.gt(p, value));
                    } else if (key.endsWith(MAX_QUERY) && this.isNumericType(value)) {
                        this.getColumnByField(this.getFieldName(key, MAX_QUERY), (p) -> wrapper.lt(p, value));
                    } else {
                        Collection list;
                        String colName;
                        if ((key.endsWith(NOT_LIST_QUERY) || key.endsWith(NOT_SET_QUERY)) && this.isCollectionType(value)) {
                            if (!CollectionUtils.sizeIsEmpty(value)) {
                                list = (Collection)value;
                                if (key.endsWith(NOT_LIST_QUERY)) {
                                    colName = this.getFieldName(key, NOT_LIST_QUERY);
                                } else {
                                    colName = this.getFieldName(key, LIST_QUERY);
                                }

                                this.getColumnByField(colName, (p) -> wrapper.notIn(p, list));
                            }
                        } else if ((key.endsWith(LIST_QUERY) || key.endsWith(SET_QUERY)) && this.isCollectionType(value)) {
                            if (!CollectionUtils.sizeIsEmpty(value)) {
                                list = (Collection)value;
                                if (key.endsWith(LIST_QUERY)) {
                                    colName = this.getFieldName(key, LIST_QUERY);
                                } else {
                                    colName = this.getFieldName(key, SET_QUERY);
                                }

                                this.getColumnByField(colName, (p) -> wrapper.in(p, list));
                            }
                        } else if (key.endsWith(LIKE_QUERY) && value instanceof CharSequence) {
                            this.getColumnByField(this.getFieldName(key, LIKE_QUERY), (p) -> wrapper.like(p, value));
                        } else if (key.endsWith(LIKE_LEFT_QUERY) && value instanceof CharSequence) {
                            this.getColumnByField(this.getFieldName(key, LIKE_LEFT_QUERY), (p) -> wrapper.likeLeft(p, value));
                        } else if (key.endsWith(LIKE_RIGHT_QUERY) && value instanceof CharSequence) {
                            this.getColumnByField(this.getFieldName(key, LIKE_RIGHT_QUERY), (p) -> wrapper.likeRight(p, value));
                        } else if (key.endsWith(NOT_EQUALS_QUERY)) {
                            this.getColumnByField(this.getFieldName(key, NOT_EQUALS_QUERY), (p) -> wrapper.ne(p, value));
                        } else {
                            this.getColumnByField(key, (p) -> wrapper.eq(p, value));
                        }
                    }
                }
            }
        }
    }

    protected QueryWrapper<T> getWrapper(Q queryParam) {
        Map<String, Object> mapQuery = Converter.objectToMap(queryParam);
        return this.getWrapper(mapQuery);
    }

    protected QueryWrapper<T> getKeyWrapper(String key) {
        if (StringUtils.isBlank(this.tableScheme.bizKeyColumn)) {
            throw new IllegalArgumentException("当前entity实体没找到业务key字段，请在entity实体中使用@BizKey注解标记对应的字段！");
        } else {
            QueryWrapper<T> wrapper = this.getDefaultWrapper();
            wrapper.eq(this.tableScheme.bizKeyColumn, key);
            return wrapper;
        }
    }

    protected QueryWrapper<T> getKeyWrapper(Collection<String> keys) {
        if (StringUtils.isBlank(this.tableScheme.bizKeyColumn)) {
            throw new IllegalArgumentException("当前entity实体没找到业务key字段，请在entity实体中使用@BizKey注解标记对应的字段！");
        } else {
            QueryWrapper<T> wrapper = this.getDefaultWrapper();
            wrapper.in(this.tableScheme.bizKeyColumn, keys);
            return wrapper;
        }
    }

    protected QueryWrapper<T> getDefaultWrapper() {
        QueryWrapper<T> wrapper = new QueryWrapper();
        wrapper.eq("active", ActiveEnum.NORMAL.getCode());
        return wrapper;
    }

    protected SqlSessionFactory sqlSessionFactory() {
        return GlobalConfigUtils.currentSessionFactory(this.entityClass);
    }

    protected SqlSession sqlSession() {
        return SqlSessionUtils.getSqlSession(this.sqlSessionFactory());
    }

    protected SqlSession sqlSessionBatch() {
        return SqlHelper.sqlSessionBatch(this.entityClass);
    }

    protected void closeSqlSession(SqlSession sqlSession) {
        SqlSessionUtils.closeSqlSession(sqlSession, GlobalConfigUtils.currentSessionFactory(this.entityClass));
    }

    protected void clearSqlSessionCache() {
        SqlSessionHolder sqlSessionHolder = (SqlSessionHolder)TransactionSynchronizationManager.getResource(this.sqlSessionFactory());
        boolean transaction = TransactionSynchronizationManager.isSynchronizationActive();
        if (sqlSessionHolder != null) {
            SqlSession sqlSession = sqlSessionHolder.getSqlSession();
            sqlSession.commit(!transaction);
        }

    }

    @SuppressWarnings("all")
    protected String sqlStatement(SqlMethod sqlMethod) {
        return SqlHelper.table(this.entityClass).getSqlStatement(sqlMethod.getMethod());
    }

    @Transactional(
            rollbackFor = {Exception.class}
    )
    protected boolean insertBatch(Collection<T> entityList, int batchSize) {
        Assert.isFalse(batchSize < 1, "batchSize must not be less than one", new Object[0]);
        if (CollUtil.isEmpty(entityList)) {
            log.warn("batch function param is empty or null");
            return false;
        } else {
            this.clearSqlSessionCache();
            SqlSession batchSqlSession = this.sqlSessionBatch();
            int i = 0;
            String sqlStatement = this.sqlStatement(SqlMethod.INSERT_ONE);

            try {
                for(Iterator<T> var6 = entityList.iterator(); var6.hasNext(); ++i) {
                    T anEntityList = var6.next();
                    batchSqlSession.insert(sqlStatement, anEntityList);
                    if (i >= 1 && i % batchSize == 0) {
                        batchSqlSession.flushStatements();
                    }
                }

                batchSqlSession.flushStatements();
                return true;
            } finally {
                this.closeSqlSession(batchSqlSession);
            }
        }
    }

    @Transactional(rollbackFor = {Exception.class})
    protected boolean updateBatch(Collection<T> entityList, int batchSize) {
        Assert.isFalse(batchSize < 1, "batchSize must not be less than one", new Object[0]);
        if (CollUtil.isEmpty(entityList)) {
            log.warn("batch function param is empty or null");
            return false;
        } else {
            this.clearSqlSessionCache();
            SqlSession batchSqlSession = this.sqlSessionBatch();
            int i = 0;
            String sqlStatement = this.sqlStatement(SqlMethod.UPDATE_BY_ID);

            try {
                for(Iterator<T> var6 = entityList.iterator(); var6.hasNext(); ++i) {
                    T anEntityList = var6.next();
                    ParamMap<T> param = new ParamMap();
                    param.put("et", anEntityList);
                    batchSqlSession.update(sqlStatement, param);
                    if (i >= 1 && i % batchSize == 0) {
                        batchSqlSession.flushStatements();
                    }
                }

                batchSqlSession.flushStatements();
                return true;
            } finally {
                this.closeSqlSession(batchSqlSession);
            }
        }
    }

    protected static <S, T> Page<T> mapTo(IPage<S> source, Class<T> tClass) {
        return new Page(Converter.copy(source.getRecords(), tClass),source.getTotal());
    }

    protected static <S> Page<S> mapTo(IPage<S> source) {
        return new Page(source.getRecords(),source.getTotal());
    }

    protected boolean isCollectionType(Object o) {
        return o instanceof Collection;
    }

    protected boolean isDateType(Object o) {
        return o instanceof Date || o instanceof LocalDateTime || o instanceof LocalDate || o instanceof LocalTime;
    }

    protected boolean isNumericType(Object o) {
        return o instanceof Integer || o instanceof Long || o instanceof Float || o instanceof Double || o instanceof BigDecimal;
    }

    private void initTableInfo() {
        this.tableScheme = this.getTableScheme(this.entityClass);
    }

    private boolean isStringBlank(Object value) {
        return value instanceof CharSequence && StringUtils.isBlank((CharSequence)value);
    }

    private String getFieldName(String fieldName, String queryAction) {
        return fieldName.substring(0, fieldName.length() - queryAction.length());
    }

    protected void getColumnByField(String fieldName, Consumer<String> action) {
        if (this.tableScheme.getMapField2Column().containsKey(fieldName)) {
            String column = (String)this.tableScheme.getMapField2Column().get(fieldName);
            action.accept(column);
        }

    }

    protected void copyProperties(Object source, Object target) {
        BeanUtils.copyProperties(source, target);
    }

    protected void copyProperties(Collection sourceList, Collection targetList) {
        Iterator itSource = sourceList.iterator();
        Iterator itTarget = targetList.iterator();

        while(itSource.hasNext()) {
            Object source = itSource.next();
            Object target = itTarget.next();
            this.copyProperties(source, target);
        }

    }

    protected String getKeyValue(T entity) {
        try {
            Object value = this.tableScheme.bizKeyField.get(entity);
            return value != null ? value.toString() : null;
        } catch (IllegalAccessException | IllegalArgumentException var3) {
            log.error("获取当前实体对象的key值出现错误！", var3);
            throw new IllegalArgumentException("获取当前实体对象的key值出现错误!");
        }
    }

    protected void setKeyValue(T entity, String key) {
        try {
            this.tableScheme.bizKeyField.set(entity, key);
        } catch (IllegalAccessException | IllegalArgumentException var4) {
            log.error("设置当前实体对象的key值出现错误！", var4);
            throw new IllegalArgumentException("设置当前实体对象的key值出现错误!");
        }
    }

    protected List<OrderItem> getOrderBy(List<SortParam> sorts) {
        if (CollUtil.isEmpty(sorts)) {
            return Collections.emptyList();
        } else {
            List<OrderItem> orderItems = new ArrayList();
            Iterator var3 = sorts.iterator();

            while(var3.hasNext()) {
                SortParam sp = (SortParam)var3.next();
                OrderItem item = this.getOrderItem(sp.getSortField(), sp.getSortType());
                orderItems.add(item);
            }

            return orderItems;
        }
    }

    protected List<OrderItem> getOrderBy(String sortsStr) {
        if (StringUtils.isBlank(sortsStr)) {
            return Collections.emptyList();
        } else {
            List<OrderItem> orderItems = new ArrayList();
            String[] sorts = sortsStr.trim().split(",");
            String[] var4 = sorts;
            int var5 = sorts.length;

            for(int var6 = 0; var6 < var5; ++var6) {
                String spStr = var4[var6];
                String[] sps = spStr.trim().split(" ");
                String col = sps[0];
                String type = "ASC";
                if (sps.length >= 2) {
                    type = sps[1];
                }

                OrderItem item = this.getOrderItem(col, type);
                orderItems.add(item);
            }

            return orderItems;
        }
    }

    protected <T> List<OrderItem> checkOrderBy(List<SortParam> sorts, Class<T> tClass) {
        if (CollUtil.isEmpty(sorts)) {
            return Collections.emptyList();
        } else {
            TableScheme tableScheme = this.getTableScheme(tClass);
            return this.checkOrderBy(sorts, tableScheme);
        }
    }

    protected List<OrderItem> checkOrderBy(List<SortParam> sorts, TableScheme tableScheme) {
        if (CollUtil.isEmpty(sorts)) {
            return Collections.emptyList();
        } else {
            List<OrderItem> orderItems = new ArrayList();
            Iterator var4 = sorts.iterator();

            while(var4.hasNext()) {
                SortParam sp = (SortParam)var4.next();
                String field = sp.getSortField();
                String type = sp.getSortType();
                String key = field.replace("_", "").toLowerCase();
                if (!tableScheme.getMapField2Column().containsKey(key)) {
                    throw new IllegalArgumentException(String.format("[%s]字段不存在，无法进行排序操作！", field));
                }

                String col = (String)tableScheme.getMapField2Column().get(key);
                OrderItem item = this.getOrderItem(col, type);
                orderItems.add(item);
            }

            return orderItems;
        }
    }

    private OrderItem getOrderItem(String col, String type) {
        return type != null && "DESC".equals(type.toUpperCase()) ? OrderItem.desc(col) : OrderItem.asc(col);
    }

    protected <T> boolean checkIsDataColumn(String fieldName, Class<T> tClass) {
        if (StringUtils.isBlank(fieldName)) {
            return false;
        } else {
            Field field = FieldUtils.getField(tClass, fieldName, true);
            if (field == null) {
                return false;
            } else {
                TableField column = field.getAnnotation(TableField.class);
                return column != null && column.exist();
            }
        }
    }

    protected static String humpToLine(String humpString) {
        Matcher matcher = HUMP_PATTERN.matcher(humpString);
        StringBuffer sb = new StringBuffer();

        while(matcher.find()) {
            matcher.appendReplacement(sb, "_" + matcher.group(0).toLowerCase());
        }

        matcher.appendTail(sb);
        return sb.toString();
    }

    protected <T> TableScheme getTableScheme(Class<T> tClass) {
        if (tClass == null) {
            return null;
        } else {
            TableScheme tableScheme = new TableScheme();
            TableName table = tClass.getAnnotation(TableName.class);
            if (table == null) {
                return null;
            } else {
                tableScheme.setTableName(table.value());
                List<Field> fields = FieldUtils.getAllFieldsList(tClass);
                fields = fields.stream().filter((p) -> !Modifier.isStatic(p.getModifiers())).collect(Collectors.toList());
                if (CollUtil.isEmpty(fields)) {
                    return tableScheme;
                } else {
                    tableScheme.mapField2Column = new HashMap(fields.size());
                    Iterator var5 = fields.iterator();

                    while(var5.hasNext()) {
                        Field item = (Field)var5.next();
                        TableField annotation = (TableField)item.getAnnotation(TableField.class);
                        String fieldName = item.getName();
                        String column = null;
                        if (annotation != null) {
                            column = annotation.value();
                        } else {
                            column = humpToLine(fieldName);
                        }

                        tableScheme.mapField2Column.put(fieldName.toLowerCase(), column);
                        if (item.getAnnotation(BizKey.class) != null) {
                            tableScheme.bizKeyField = item;
                            tableScheme.bizKeyField.setAccessible(true);
                            tableScheme.bizKeyColumn = column;
                        }
                    }

                    return tableScheme;
                }
            }
        }
    }

    public Class<T> getEntityClass() {
        return this.entityClass;
    }

    public Class<D> getDtoClass() {
        return this.dtoClass;
    }

    public TableScheme getTableScheme() {
        return this.tableScheme;
    }

    private static enum ActiveEnum {
        NORMAL(1, "正常"),
        DELETE(0, "删除");

        private Integer code;
        private String desc;

        private ActiveEnum(Integer code, String desc) {
            this.code = code;
            this.desc = desc;
        }

        public Integer getCode() {
            return this.code;
        }

        public String getDesc() {
            return this.desc;
        }
    }

    public class TableScheme {
        private Field bizKeyField;
        private String bizKeyColumn;
        private String tableName;
        private Map<String, String> mapField2Column;

        public TableScheme() {
        }

        public Field getBizKeyField() {
            return this.bizKeyField;
        }

        public String getBizKeyColumn() {
            return this.bizKeyColumn;
        }

        public String getTableName() {
            return this.tableName;
        }

        public Map<String, String> getMapField2Column() {
            return this.mapField2Column;
        }

        public void setBizKeyField(Field bizKeyField) {
            this.bizKeyField = bizKeyField;
        }

        public void setBizKeyColumn(String bizKeyColumn) {
            this.bizKeyColumn = bizKeyColumn;
        }

        public void setTableName(String tableName) {
            this.tableName = tableName;
        }

        public void setMapField2Column(Map<String, String> mapField2Column) {
            this.mapField2Column = mapField2Column;
        }

        public String toString() {
            return "BaseRepositoryImpl.TableScheme(bizKeyField=" + this.getBizKeyField() + ", bizKeyColumn=" + this.getBizKeyColumn() + ", tableName=" + this.getTableName() + ", mapField2Column=" + this.getMapField2Column() + ")";
        }
    }
}
